/*
MIT License

Copyright (c) 2022 МГТУ им. Н.Э. Баумана, кафедра ИУ-6, Михаил Фетисов,

https://bmstu.codes/lsx/simodo/loom
*/

#ifndef simodo_interpret_host_base_Machine
#define simodo_interpret_host_base_Machine

/*! \file BaseMachine.h
    \brief Класс управления состоянием машины SBL
*/

#include "simodo/variable/VariableStack.h"
#include "simodo/variable/VariableSetWrapper.h"
#include "simodo/parser/fuze/BaseOperationCode.h"


namespace simodo::interpret::builtins
{
    class BaseMachine
    {
        /// \todo Скорее всего нужно выносить всё состояние машины в отдельный класс!

        const inout::uri_set_t &        _files;

        mutable variable::VariableStack _stack;
        std::vector<size_t>             _local_scope;
        variable::Variable              _return_variable;

    public:
        BaseMachine() = delete;
        BaseMachine(const inout::uri_set_t & files);

    public:
        const variable::VariableStack & stack()           const { return _stack; } 
        variable::VariableStack &       stack()                 { return _stack; } 
        const variable::Variable &      return_variable() const { return _return_variable; }
        const std::vector<size_t> &     local_scope()     const { return _local_scope; }

        void setReturnVariable(variable::Variable return_variable) { _return_variable = return_variable; }

    public:
        void                    reset();
        void                    push(variable::Variable v);
        void                    pushRef(const variable::Variable & v, const inout::TokenLocation & location);
        void                    pushRef(variable::VariableRef ref);
        variable::Variable      pop();
        void                    popAmount(size_t n);
        variable::VariableRef   findVariable(const inout::Token & variable_name) const;
        variable::VariableRef   find(variable::VariableSetWrapper & search_area, const std::u16string & variable_name) const;
        void                    checkProcedureCalled();

        variable::Variable      createVariable_implicit(const inout::Token & constant_value) const;
        variable::Value         callFunction_implicit(const inout::Token & dot, size_t args_stack_position);
        variable::Variable      getElement_implicit(const inout::Token & dot, const inout::Token & variable_name);
    };
}

#endif // simodo_interpret_host_base_Machine
